package com.laycoding.layrpc.config.server;


import com.laycoding.layrpc.annotation.LayRpcService;
import com.laycoding.layrpc.common.LayRpcServiceCache;
import com.laycoding.layrpc.entity.LayRpcProperties;
import com.laycoding.layrpc.handler.server.MyChannelHandler;
import com.laycoding.layrpc.util.IpUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.util.StringUtils;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class RpcServerCommandLine implements CommandLineRunner {
    @Autowired
    private LayRpcRegistry layRpcRegistry;

    private LayRpcProperties layRpcProperties;


    private static List<String> classList = new ArrayList<>();

    public RpcServerCommandLine(LayRpcProperties layRpcProperties) {
        this.layRpcProperties = layRpcProperties;
        scanPackage(layRpcProperties.getBasePackage());
    }

    @Override
    public void run(String... args) throws Exception {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            ServerBootstrap group = serverBootstrap.group(bossGroup, workGroup);
            group.channel(NioServerSocketChannel.class).childHandler(new MyChannelHandler())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            Integer serverPort = layRpcProperties.getServerPort();
            ChannelFuture channelFuture = serverBootstrap.bind(serverPort).sync();
            layRpcRegistry.doReginstry(layRpcProperties.getPath() + "/", IpUtils.getIp() + ":" + serverPort, layRpcProperties.getServiceName());
            log.info("LayRpc Registry start listen at " + serverPort + "success");
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    private void registryService() {
        if (classList.size() == 0) {
            return;
        }
        for (String className : classList) {
            try {
                Class<?> clazz = Class.forName(className);
                // 服务名称
                LayRpcService declaredAnnotation = clazz.getDeclaredAnnotation(LayRpcService.class);
                if (!StringUtils.isEmpty(declaredAnnotation) && clazz.getInterfaces().length > 0) {
                    Class<?> anInterface = clazz.getInterfaces()[0];
                    LayRpcServiceCache.put(anInterface.getName(), clazz.newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void scanPackage(String packageName) {
        ClassLoader classLoader = this.getClass().getClassLoader();
        URL url = classLoader.getResource(packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        File[] files = dir.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                scanPackage(packageName + "." + file.getName());
            } else {
                // 拿出类名
                String className = packageName + "." + file.getName().replace(".class", "").trim();
                classList.add(className);
            }
        }
        registryService();
    }


}
